package com.turtle3d.user.grammars;

import java.util.ArrayList;

import com.turtle3d.formallanguage.grammar.Production;
import com.turtle3d.formallanguage.parser.SimpleParser;
import com.turtle3d.formallanguage.symbol.Condition;
import com.turtle3d.formallanguage.symbol.Method;
import com.turtle3d.formallanguage.symbol.Symbol;
import com.turtle3d.formallanguage.symbol.SymbolFactory;
import com.turtle3d.util.Randomizer;

/**
 * Advanced tree grammar. Independently set growth radius and height, 
 * branch angle variation, chance for bud death and bud delay.
 * @author Marek Paterczyk <marek.paterczyk@gmail.com>
 *
 */
public class Tree3Apple extends Tree3
{		
	
	@Override
	public void define(){
		
		Symbol axiom = SymbolFactory.getSymbolFactory().createSymbolofClass("K");		
		setAxiom(axiom);
		
		/*Trunk growth*/		
		SymbolFactory.getSymbolFactory().registerSymbolClass("F", "F(grow)", new Method(){
			public boolean calculate(ArrayList<Symbol> symbolSequence, int symbolIndex, Symbol calculatedSymbol)
			{
				Float r = calculatedSymbol.getParameter(Symbol.RADIUS);
				Float r_mul = calculatedSymbol.getParameter("radiusMultiplier");
				calculatedSymbol.setParameter(Symbol.RADIUS, r*r_mul);
				
				Float d = calculatedSymbol.getParameter(Symbol.DISTANCE);				
				Float d_mul_mul = calculatedSymbol.getParameter("distanceMultiplierMultiplier");
				Float d_mul = 1+(calculatedSymbol.getParameter("distanceMultiplier")-1)*d_mul_mul;
				calculatedSymbol.setParameter(Symbol.DISTANCE, d*d_mul+calculatedSymbol.getParameter("distanceVariation")*d*Randomizer.getRandomizer().nextVariation());
				calculatedSymbol.setParameter("distanceMultiplier", d_mul);
				
				return true;
				
			}
		});
			
		/*Bud death*/
		SymbolFactory.getSymbolFactory().registerSymbolClass("B", "B", new Method(){
			public boolean calculate(ArrayList<Symbol> symbolSequence, int symbolIndex, Symbol calculatedSymbol)
			{				
				return Randomizer.getRandomizer().getRandom().nextFloat()>calculatedSymbol.getParameter("budDeathChance");
			}			
		});		
		
		
		addProduction(SimpleParser.parseProduction("K->F[+RB][>>+RB][>>>>+RB][RB(main)]"));
		/*Main trunk uses different values for bud death and bud delay chance*/ 
		SymbolFactory.getSymbolFactory().registerSymbolClass("B", "B(main)", new Method(){
			public boolean calculate(ArrayList<Symbol> symbolSequence, int symbolIndex, Symbol calculatedSymbol) {
				calculatedSymbol.setParameter("budDelayChance", calculatedSymbol.getParameter("budDelayChanceMainTrunk"));
				calculatedSymbol.setParameter("budDeathChance", calculatedSymbol.getParameter("budDeathChanceMainTrunk"));
				return true;
			};
		});
		Production p = SimpleParser.parseProduction("B->>[+RL][>>+RL][>>>>+RL]F[+RB][>>+RB][>>>>+RB][RB]");
		/*Bud delay*/
		p.setCondition(new Condition(){
			public boolean check(ArrayList<Symbol> symbolSequence, int symbolIndex) {
				Symbol calculatedSymbol = symbolSequence.get(symbolIndex);
				float i = calculatedSymbol.getBirthIteration();
				float iC = calculatedSymbol.getParameter("iterationsCount");				
				return Randomizer.getRandomizer().getRandom().nextFloat()>calculatedSymbol.getParameter("budDelayChance");
			}
			
		});				
		addProduction(p);
		addProduction(SimpleParser.parseProduction("F->F(grow)"));				
						
	}
	
	@Override
	public void setRequiredParameters(){
		setRequiredParameter(Symbol.RADIUS, 0.08f);
		setRequiredParameter("radiusMultiplier", 1.76f);
		setRequiredParameter(Symbol.DISTANCE, 0.2f);
		setRequiredParameter("distanceMultiplier", 1.5f);				
		setRequiredParameter(Symbol.TURN_ANGLE, 45f);
		setRequiredParameter(Symbol.ROLL_ANGLE, 60f);	
		setRequiredParameter("budDelayChance", 0.3f);
		setRequiredParameter("budDeathChance", 0.1f);
		setRequiredParameter("budDelayChanceMainTrunk", 0.1f);
		setRequiredParameter("budDeathChanceMainTrunk", 0.1f);
		setRequiredParameter("distanceMultiplierMultiplier", 0.8f);
		setRequiredParameter("distanceVariation", 0.1f);
		
	}

}
